package base.thread.readwritelock;

import java.util.Calendar;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {
	ReadWriteLock lock=null;
	Lock readLock=null;
	Lock writeLock=null;
	int key=100;
	int index=100;
	Map<Integer, String> dataMap=null;
	public ReadWriteLockDemo(){
		lock=new ReentrantReadWriteLock(true);
		readLock=lock.readLock();
		writeLock=lock.writeLock();
		dataMap=new TreeMap<Integer, String>();
	}
	
	public static void main(String[] args) {
		ReadWriteLockDemo tester=new ReadWriteLockDemo();
		tester.writeLock.lock();
		System.out.println(Thread.currentThread().getName()+" get writeLock.");
		tester.writeLock.lock();
		System.out.println(Thread.currentThread().getName()+" get writeLock.");
		
		tester.readLock.lock();
		System.out.println(Thread.currentThread().getName()+" get readLock.");
		tester.readLock.lock();
		System.out.println(Thread.currentThread().getName()+" get readLock.");
		
		tester.readLock.unlock();
		tester.readLock.unlock();
		
		tester.writeLock.unlock();
		tester.writeLock.unlock();
		tester.test();
	}
	
	public void test(){
		for( int i=0;i<10;i++){
			new Thread(new Reader(this)).start();
		}
		for( int i=0;i<3;i++){
			new Thread(new Writer(this)).start();
		}
	}
	
	public void read(){
		readLock.lock();
		try {
			if(dataMap.isEmpty()){
				Calendar now=Calendar.getInstance();
				System.out.println(now.getTime().getTime()+" R "+Thread.currentThread().getName()+" get key,but map is empty.");
			}
			String value=dataMap.get(index);
			Calendar now=Calendar.getInstance();
			System.out.println(now.getTime().getTime()+" R "+Thread.currentThread().getName()+"key="+index+" value="+value+" map size="+dataMap.size());
			
			try {
				Thread.sleep(3000);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} finally{
			readLock.unlock();
		}
		
		
	}
	
	public void write(){
		writeLock.lock();
		try {
			String value="value"+key;
			dataMap.put(new Integer(key), value);
			Calendar now=Calendar.getInstance();
			System.out.println(now.getTime().getTime()+" W "+Thread.currentThread().getName()+"key="+index+" value="+value+" map size="+dataMap.size());
			key++;
			try {
				Thread.sleep(500);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} finally{
			writeLock.unlock();
		}
	}
	
}
class Reader implements Runnable{
	ReadWriteLockDemo tester=null;
	Reader(ReadWriteLockDemo tester){
		this.tester=tester;
	}
	
	public void run() {
		Calendar now=Calendar.getInstance();
		System.out.println(now.getTime().getTime()+" R "+Thread.currentThread().getName()+" started");
		for(int i=0;i<10;i++){
			tester.read();
		}
	}
}

class Writer implements Runnable{
	ReadWriteLockDemo tester=null;
	Writer(ReadWriteLockDemo tester){
		this.tester=tester;
	}
	
	public void run() {
		Calendar now=Calendar.getInstance();
		System.out.println(now.getTime().getTime()+" R "+Thread.currentThread().getName()+" started");
		for(int i=0;i<10;i++){
			tester.write();
		}
	}
}
